
import 'package:collection/collection.dart';
import 'package:easy_refresh/easy_refresh.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:im_app/im/util/ImSingleton.dart';
import 'package:logger/logger.dart';

import '../../dao/ImUserAndGroupDao.dart';
import '../../pojo/Enums.dart';
import '../../pojo/UiPojo.dart';
import '../../util/DbUtil.dart';

final class UserAndGroupListCubit extends Cubit<UserGroupListState> {

  UserAndGroupListCubit() : super(const UserGroupListState.loading());


  final _logger = Logger(printer: PrettyPrinter(),);
  
  int _pageStart = 0;
  final int _pageSize = 10000;

  Future<void> loadData() async {
    try {
      final userGroupDao = ImUserAndGroupDao();
      _pageStart = 0;
      var userId = ImSingleton.getInstance().session.userId;
      final userGroups = await userGroupDao.getNewByStartId(userId!, _pageStart, _pageSize);
      var letterInfo = UserGroupListState.buildLetters(userGroups);
      emit(UserGroupListState.success(userGroups, letterInfo.letters, letterInfo.letterSizeMap));
    } catch(error, stracktrace) {
      _logger.e("load data error", error: error, stackTrace: stracktrace);
      emit(const UserGroupListState.failure());
    }
  }

  Future<IndicatorResult> loadMoreData() async {
    try {
      final userGroupDao = ImUserAndGroupDao();

      _pageStart = state.userGroups.length;
      var userId = ImSingleton.getInstance().session.userId;
      final userGroups = await userGroupDao.getNewByStartId(userId!, _pageStart, _pageSize);
      await Future.delayed(const Duration(milliseconds: 1000));
      if (userGroups.isEmpty) {
        return IndicatorResult.noMore;
      }
      final List<ImUserAndGroup> lastedUserGroups = List.of(state.userGroups);
      lastedUserGroups.addAll(userGroups);
      var letterInfo = UserGroupListState.buildLetters(lastedUserGroups);
      emit(UserGroupListState.success(lastedUserGroups, letterInfo.letters, letterInfo.letterSizeMap));
      return IndicatorResult.success;
    } on Exception {
      emit(const UserGroupListState.failure());
      return IndicatorResult.fail;
    }
  }
}

final class UserGroupListState extends Equatable {
  final LoadingState state;
  final List<ImUserAndGroup> userGroups;
  final List<String> letters;
  final Map<String, int> letterSizeMap;

  const UserGroupListState._({
    this.state = LoadingState.loading,
    this.userGroups = const <ImUserAndGroup>[],
    this.letters = const <String>[],
    this.letterSizeMap = const {},
  });

  const UserGroupListState.loading() : this._();

  const UserGroupListState.success(List<ImUserAndGroup> userGroups, List<String> letters, Map<String, int> letterSizeMap)
      : this._(state: LoadingState.success, userGroups: userGroups, letters: letters, letterSizeMap: letterSizeMap);

  const UserGroupListState.failure() : this._(state: LoadingState.failure);

  @override
  List<Object?> get props => [state, userGroups];

  static LetterInfo buildLetters(List<ImUserAndGroup> userGroups){
    Map<String, List<ImUserAndGroup>> grouped = groupBy(userGroups, (value) => (value.firstLetter??'').toUpperCase());
    var newLetter = <String>[];
    var letterSizeMap = <String, int>{};
    grouped.forEach((key, value){
      letterSizeMap[key] = value.length;
      print('$key size: ${value.length}');
      newLetter.add(key.toUpperCase());
    });
    newLetter.sort((k1, k2)=>Comparable.compare(k1, k2));
    return LetterInfo(letters: newLetter, letterSizeMap: letterSizeMap);
  }
}

final class LetterInfo {
  final List<String> letters;
  final Map<String, int> letterSizeMap;

  const LetterInfo({required this.letters, required this.letterSizeMap});
}



